package com.suprema.biomini;

import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.HeadlessException;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 將指紋直接繪製於 Frame
 * @author Kent Yeh
 */
public class FingerFrame extends Frame implements Fingerprintable {

    protected static Logger logger = LoggerFactory.getLogger(FingerJFrame.class);
    private SFRDevice device;
    private boolean core = false;
    private int padding = 3;
    private int fpLeftTopX = padding;
    private int fpLeftTopY = padding;
    private int fpWidth = 280;
    private int fpHeight = 320;
    private int diffX = 4;
    private int diffY = 23;
    private boolean showBorder = true;
    private boolean expDebug = false;

    public FingerFrame(String title, GraphicsConfiguration gc, SFRDevice device) {
        super(title, gc);
        this.device = device;
        frameInit();
    }

    public FingerFrame(String title, SFRDevice device) throws HeadlessException {
        super(title);
        this.device = device;
        frameInit();
    }

    public FingerFrame(GraphicsConfiguration gc, SFRDevice device) {
        super(gc);
        this.device = device;
        frameInit();
    }

    public FingerFrame(SFRDevice device) throws HeadlessException {
        this.device = device;
        frameInit();
    }

    @Override
    public boolean isCore() {
        return core;
    }

    /**
     *  Specifies whether the core of fingerprint is drawn of not.   
     * @param core 
     */
    public void setCore(boolean core) {
        this.core = core;
    }

    /**
     * {@inheritDoc }
     * @return 左右偏義量, 預設為 3
     */
    @Override
    public int getDiffX() {
        return diffX;
    }

    @Override
    public void setDiffX(int diffX) {
        this.diffX = diffX;
    }

    /**
     * {@inheritDoc }
     * @return 上下偏義量, 預設為 22
     */
    @Override
    public int getDiffY() {
        return diffY;
    }

    @Override
    public void setDiffY(int diffY) {
        this.diffY = diffY;
    }

    /**
     * 設定繪製指紋高度
     * @return 繪製指紋高度 
     */
    public int getFpHeight() {
        return fpHeight;
    }

    /**
     * 設定繪製指紋高度
     * @param fpHeight 繪製指紋高度
     */
    public void setFpHeight(int fpHeight) {
        this.fpHeight = fpHeight;
    }

    public int getFpLeftTopX() {
        return fpLeftTopX;
    }

    public void setFpLeftTopX(int fpLeftTopX) {
        this.fpLeftTopX = fpLeftTopX;
    }

    public int getFpLeftTopY() {
        return fpLeftTopY;
    }

    public void setFpLeftTopY(int fpLeftTopY) {
        this.fpLeftTopY = fpLeftTopY;
    }

    public void setFpLeftTop(int x, int y) {
        setFpLeftTopX(x);
        setFpLeftTopY(y);
    }

    /**
     * 設定繪製指紋寬度
     * @return 繪製指紋寬度
     */
    public int getFpWidth() {
        return fpWidth;
    }

    /**
     * 設定繪製指紋寬度
     * @param fpWidth 繪製指紋寬度
     */
    public void setFpWidth(int fpWidth) {
        this.fpWidth = fpWidth;
    }

    /**
     * 設定繪製指紋大小
     * @param w 寬度
     * @param h 高度
     */
    public void setFpSize(int w, int h) {
        setFpWidth(w);
        setFpHeight(h);
    }

    @Override
    public int getPadding() {
        return padding;
    }

    /**
     * 設定繪圖與邊界的空隙
     * @param padding 空隙
     */
    public void setPadding(int padding) {
        this.padding = padding;
    }

    protected void frameInit() {
        setPreferredSize(new Dimension(300, 319));
        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                SFRDevice.unload();
            }

            @Override
            public void windowOpened(WindowEvent e) {
                logger.debug("左:{},上:{},右:{},下:{},寬:{},高:{},隔:{}", new Object[]{getClientFpLeftTopX(), getClientFpLeftTopY(),
                            getClientFpBottomRightX(), getClientFpBottomRightY(),
                            getPainterBoxWidth(), getPainterBoxHeight(), padding});
            }
        });
        addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent e) {
                super.componentResized(e);
                expDebug = false;
                repaint();
            }
        });
    }

    public int getClientWidth() {
        return getSize().width - this.getInsets().left - this.getInsets().right;
    }

    public int getClientHeight() {
        return getSize().height - this.getInsets().top - this.getInsets().bottom;
    }

    public int getFpBorderLeftTopX() {
        return fpLeftTopX + this.getInsets().left > 0 ? fpLeftTopX + this.getInsets().left : this.getInsets().left;
    }

    public int getFpBorderLeftTopY() {
        return fpLeftTopY + this.getInsets().top > 0 ? fpLeftTopY + this.getInsets().top : this.getInsets().top;
    }

    @Override
    public int getClientFpLeftTopX() {
        return fpLeftTopX + padding + this.getInsets().left > 0 ? fpLeftTopX + padding + this.getInsets().left : this.getInsets().left;
    }

    @Override
    public int getClientFpLeftTopY() {
        return fpLeftTopY + padding + this.getInsets().top > 0 ? fpLeftTopY + padding + this.getInsets().top : this.getInsets().top;
    }

    @Override
    public int getClientFpBottomRightX() {
        int x = getClientFpLeftTopX() + getFpWidth() - 2 * padding;
        return x > getSize().width ? getSize().width - this.getInsets().right : x;

    }

    @Override
    public int getClientFpBottomRightY() {
        int y = getClientFpLeftTopY() + getFpHeight() - 2 * padding;
        return y > getSize().height ? getSize().height - this.getInsets().bottom : y;
    }

    public int getPainterBoxHeight() {
        return getClientFpBottomRightY() - getClientFpLeftTopY();
    }

    public int getPainterBoxWidth() {
        return getClientFpBottomRightX() - getClientFpLeftTopX();
    }

    /**
     * 繪圖時是否加邊框
     * @return 
     */
    public boolean isShowBorder() {
        return showBorder;
    }

    /**
     * 設定繪圖時是否加邊框
     * @param showBorder 
     */
    public void setShowBorder(boolean showBorder) {
        this.showBorder = showBorder;
    }

    @Override
    public void paint(Graphics g) {
        if (isVisible()) {
            g.clearRect(getClientFpLeftTopX(), getClientFpLeftTopY(), getPainterBoxWidth(), getPainterBoxHeight());
            int lineWidth = 1;
            if (device != null && device.isSensorOn()) {
                device.draw(this, getClientFpLeftTopX() + lineWidth - diffX, getClientFpLeftTopY() + lineWidth - diffY,
                        getClientFpBottomRightX() - lineWidth - diffX, getClientFpBottomRightY() - lineWidth - diffY, core);
                if (!expDebug) {
                    expDebug = true;
                    logger.debug("device.draw at ({},{},{},{})", new Object[]{
                                getClientFpLeftTopX() + lineWidth - diffX, getClientFpLeftTopY() + lineWidth - diffY,
                                getClientFpBottomRightX() - lineWidth - diffX, getClientFpBottomRightY() - lineWidth - diffY});
                }
            }
            if (showBorder) {
                Graphics2D g2D = (Graphics2D) g;
                g2D.setStroke(new BasicStroke(lineWidth));
                g2D.drawRect(getClientFpLeftTopX(), getClientFpLeftTopY(), getPainterBoxWidth(), getPainterBoxHeight());
            }
        }
        super.paint(g);
    }
}